{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "name": "DBN.ipynb",
      "provenance": [],
      "collapsed_sections": []
    },
    "kernelspec": {
      "name": "python3",
      "display_name": "Python 3"
    },
    "language_info": {
      "name": "python"
    },
    "accelerator": "GPU"
  },
  "cells": [
    {
      "cell_type": "code",
      "execution_count": 1,
      "metadata": {
        "id": "uCQrVzZSoFi-"
      },
      "outputs": [],
      "source": [
        "import tensorflow as tf\n",
        "import numpy as np\n",
        "import matplotlib.pyplot as plt"
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "(train_data, _), (test_data, _) =  tf.keras.datasets.mnist.load_data()\n",
        "train_data = train_data/np.float32(255)\n",
        "train_data = np.reshape(train_data, (train_data.shape[0], 784))\n",
        "\n",
        "\n",
        "test_data = test_data/np.float32(255)\n",
        "test_data = np.reshape(test_data, (test_data.shape[0], 784))"
      ],
      "metadata": {
        "id": "9os9_HheZzr_"
      },
      "execution_count": 2,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "#Class that defines the behavior of the RBM\n",
        "class RBM(object):\n",
        "    \n",
        "    def __init__(self, input_size, output_size, lr=1.0, batchsize=100):\n",
        "        \"\"\"\n",
        "        m: Number of neurons in visible layer\n",
        "        n: number of neurons in hidden layer\n",
        "        \"\"\"\n",
        "        #Defining the hyperparameters\n",
        "        self._input_size = input_size #Size of Visible\n",
        "        self._output_size = output_size #Size of outp\n",
        "        self.learning_rate = lr #The step used in gradient descent\n",
        "        self.batchsize = batchsize #The size of how much data will be used for training per sub iteration\n",
        "        \n",
        "        #Initializing weights and biases as matrices full of zeroes\n",
        "        self.w = tf.zeros([input_size, output_size], np.float32) #Creates and initializes the weights with 0\n",
        "        self.hb = tf.zeros([output_size], np.float32) #Creates and initializes the hidden biases with 0\n",
        "        self.vb = tf.zeros([input_size], np.float32) #Creates and initializes the visible biases with 0\n",
        "\n",
        "\n",
        "    #Forward Pass\n",
        "    def prob_h_given_v(self, visible, w, hb):\n",
        "        #Sigmoid \n",
        "        return tf.nn.sigmoid(tf.matmul(visible, w) + hb)\n",
        "\n",
        "    #Backward Pass\n",
        "    def prob_v_given_h(self, hidden, w, vb):\n",
        "        return tf.nn.sigmoid(tf.matmul(hidden, tf.transpose(w)) + vb)\n",
        "    \n",
        "    #Generate the sample probability\n",
        "    def sample_prob(self, probs):\n",
        "        return tf.nn.relu(tf.sign(probs - tf.random.uniform(tf.shape(probs))))\n",
        "\n",
        "    #Training method for the model\n",
        "    def train(self, X, epochs=10):\n",
        "               \n",
        "        loss = []\n",
        "        for epoch in range(epochs):\n",
        "            #For each step/batch\n",
        "            for start, end in zip(range(0, len(X), self.batchsize),range(self.batchsize,len(X), self.batchsize)):\n",
        "                batch = X[start:end]\n",
        "                    \n",
        "                #Initialize with sample probabilities\n",
        "                    \n",
        "                h0 = self.sample_prob(self.prob_h_given_v(batch, self.w, self.hb))\n",
        "                v1 = self.sample_prob(self.prob_v_given_h(h0, self.w, self.vb))\n",
        "                h1 = self.prob_h_given_v(v1, self.w, self.hb)\n",
        "                    \n",
        "                #Create the Gradients\n",
        "                positive_grad = tf.matmul(tf.transpose(batch), h0)\n",
        "                negative_grad = tf.matmul(tf.transpose(v1), h1)\n",
        "                    \n",
        "                #Update learning rates \n",
        "                self.w = self.w + self.learning_rate *(positive_grad - negative_grad) / tf.dtypes.cast(tf.shape(batch)[0],tf.float32)\n",
        "                self.vb = self.vb +  self.learning_rate * tf.reduce_mean(batch - v1, 0)\n",
        "                self.hb = self.hb +  self.learning_rate * tf.reduce_mean(h0 - h1, 0)\n",
        "                    \n",
        "            #Find the error rate\n",
        "            err = tf.reduce_mean(tf.square(batch - v1))\n",
        "            print ('Epoch: %d' % epoch,'reconstruction error: %f' % err)\n",
        "            loss.append(err)\n",
        "                    \n",
        "        return loss\n",
        "        \n",
        "    #Create expected output for our DBN\n",
        "    def rbm_output(self, X):\n",
        "        out = tf.nn.sigmoid(tf.matmul(X, self.w) + self.hb)\n",
        "        return out\n",
        "    \n",
        "    def rbm_reconstruct(self,X):\n",
        "        h = tf.nn.sigmoid(tf.matmul(X, self.w) + self.hb)\n",
        "        reconstruct = tf.nn.sigmoid(tf.matmul(h, tf.transpose(self.w)) + self.vb)\n",
        "        return reconstruct\n",
        "            "
      ],
      "metadata": {
        "id": "y9ALhkKMaKKW"
      },
      "execution_count": 3,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "RESHAPED = 784\n",
        "NB_CLASSES = 10   # number of outputs = number of digits\n",
        "\n",
        "(train_data, Y_train), (test_data, Y_test) =  tf.keras.datasets.mnist.load_data()\n",
        "train_data = train_data/np.float32(255)\n",
        "train_data = np.reshape(train_data, (train_data.shape[0], RESHAPED))\n",
        "Y_train = tf.keras.utils.to_categorical(Y_train, NB_CLASSES)\n",
        "Y_test = tf.keras.utils.to_categorical(Y_test, NB_CLASSES)\n",
        "\n",
        "test_data = test_data/np.float32(255)\n",
        "test_data = np.reshape(test_data, (test_data.shape[0], RESHAPED))"
      ],
      "metadata": {
        "id": "sEBIdtuGfUJt"
      },
      "execution_count": 4,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "RBM_hidden_sizes = [500, 200 , 50 ] #create 2 layers of RBM with size 400 and 100\n",
        "\n",
        "#Since we are training, set input as training data\n",
        "inpX = train_data\n",
        "\n",
        "#Create list to hold our RBMs\n",
        "rbm_list = []\n",
        "\n",
        "#Size of inputs is the number of inputs in the training set\n",
        "input_size = train_data.shape[1]\n",
        "\n",
        "#For each RBM we want to generate\n",
        "for i, size in enumerate(RBM_hidden_sizes):\n",
        "    print ('RBM: ',i,' ',input_size,'->', size)\n",
        "    rbm_list.append(RBM(input_size, size))\n",
        "    input_size = size\n"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "zmEKFgGKfY3D",
        "outputId": "d101b1f7-4ee5-4747-e884-e1c92888da25"
      },
      "execution_count": 5,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "RBM:  0   784 -> 500\n",
            "RBM:  1   500 -> 200\n",
            "RBM:  2   200 -> 50\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "#For each RBM in our list\n",
        "for rbm in rbm_list:\n",
        "    print ('Next RBM:')\n",
        "    #Train a new one\n",
        "    rbm.train(tf.cast(inpX,tf.float32)) \n",
        "    #Return the output layer\n",
        "    inpX = rbm.rbm_output(inpX)"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "76gVBUaSaUgz",
        "outputId": "98f15132-f2b5-4459-e07c-5da2c45c6ff6"
      },
      "execution_count": 6,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Next RBM:\n",
            "Epoch: 0 reconstruction error: 0.056434\n",
            "Epoch: 1 reconstruction error: 0.049873\n",
            "Epoch: 2 reconstruction error: 0.048256\n",
            "Epoch: 3 reconstruction error: 0.046911\n",
            "Epoch: 4 reconstruction error: 0.045232\n",
            "Epoch: 5 reconstruction error: 0.043050\n",
            "Epoch: 6 reconstruction error: 0.044899\n",
            "Epoch: 7 reconstruction error: 0.043522\n",
            "Epoch: 8 reconstruction error: 0.043156\n",
            "Epoch: 9 reconstruction error: 0.041891\n",
            "Next RBM:\n",
            "Epoch: 0 reconstruction error: 0.029479\n",
            "Epoch: 1 reconstruction error: 0.025730\n",
            "Epoch: 2 reconstruction error: 0.023860\n",
            "Epoch: 3 reconstruction error: 0.022723\n",
            "Epoch: 4 reconstruction error: 0.022520\n",
            "Epoch: 5 reconstruction error: 0.022282\n",
            "Epoch: 6 reconstruction error: 0.021761\n",
            "Epoch: 7 reconstruction error: 0.021179\n",
            "Epoch: 8 reconstruction error: 0.020641\n",
            "Epoch: 9 reconstruction error: 0.020910\n",
            "Next RBM:\n",
            "Epoch: 0 reconstruction error: 0.051618\n",
            "Epoch: 1 reconstruction error: 0.047273\n",
            "Epoch: 2 reconstruction error: 0.047277\n",
            "Epoch: 3 reconstruction error: 0.046827\n",
            "Epoch: 4 reconstruction error: 0.043969\n",
            "Epoch: 5 reconstruction error: 0.045904\n",
            "Epoch: 6 reconstruction error: 0.045189\n",
            "Epoch: 7 reconstruction error: 0.044312\n",
            "Epoch: 8 reconstruction error: 0.045055\n",
            "Epoch: 9 reconstruction error: 0.044185\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "out = rbm_list[0].rbm_reconstruct(test_data)\n",
        "# Plotting original and reconstructed images\n",
        "row, col = 2, 8\n",
        "idx = np.random.randint(0, 100, row * col // 2)\n",
        "f, axarr = plt.subplots(row, col, sharex=True, sharey=True, figsize=(20,4))\n",
        "for fig, row in zip([test_data,out], axarr):\n",
        "    for i,ax in zip(idx,row):\n",
        "        ax.imshow(tf.reshape(fig[i],[28, 28]), cmap='Greys_r')\n",
        "        ax.get_xaxis().set_visible(False)\n",
        "        ax.get_yaxis().set_visible(False)\n"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 239
        },
        "id": "0-G_oy5TadA9",
        "outputId": "e9b68910-5bd8-47e5-ece1-2706837e214a"
      },
      "execution_count": 8,
      "outputs": [
        {
          "output_type": "display_data",
          "data": {
            "image/png": "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\n",
            "text/plain": [
              "<Figure size 1440x288 with 16 Axes>"
            ]
          },
          "metadata": {
            "needs_background": "light"
          }
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        ""
      ],
      "metadata": {
        "id": "XaUn5nFAhJ1j"
      },
      "execution_count": null,
      "outputs": []
    }
  ]
}